﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using GraphSharp.Controls;
using RWGUI.Model;
using RWLibrary.Logic;
using RWLibrary.Logic.Graph;

namespace RWGUI.ViewModel
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        #region Data

        
        private GuiGraph graph;
        private Graph modelgraph;
        private List<String> layoutAlgorithmTypes = new List<string>();
        
        #endregion

        #region Ctor
        public MainWindowViewModel()
        {
            Statements = new ObservableCollection<string>();
            Statement="initially !a && b && c || a && !b && !c\n";
            Statement+=("A causes a  if b&&!a with cost 2\n");
            Statement+="B causes !a if a with cost 2\n";
            Statement+=("C causes c ||!c if !a with cost 2\n");
            Statement+=("D causes a&&b&&c if a&&!b with cost 2\n");
            Graph = new GuiGraph(true);
            //Add Layout Algorithm Types
            layoutAlgorithmTypes.Add("BoundedFR");
            layoutAlgorithmTypes.Add("Circular");
            layoutAlgorithmTypes.Add("CompoundFDP");
            layoutAlgorithmTypes.Add("EfficientSugiyama");
            layoutAlgorithmTypes.Add("FR");
            layoutAlgorithmTypes.Add("ISOM");
            layoutAlgorithmTypes.Add("KK");
            layoutAlgorithmTypes.Add("LinLog");
            layoutAlgorithmTypes.Add("Tree");

            //Pick a default Layout Algorithm Type
            
            
           



        }
        #endregion


        public void ReLayoutGraph()
        {
            try
            {
                modelgraph = new Graph(Statement);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error in world creation.");
                return;
            }
            
            
            Graph = new GuiGraph(true);
            foreach (Node vertex in modelgraph.Nodes)
            {
                Graph.AddVertex(vertex);
                //AddNewGraphEdge(vertex, modelgraph.Nodes[1]);
                vertex.Description = null;
            }

            
            foreach (Node vertex in Graph.Vertices)
            {
                foreach (KeyValuePair<Edge, Node> connection in vertex.Connections)
                    if(connection.Value.Equals(vertex))
                    {
                        if(string.IsNullOrEmpty( vertex.Description))
                            vertex.Description = connection.Key.ToString();
                        else
                            vertex.Description += Environment.NewLine + connection.Key;
                    }
                    else
                {
                    GuiEdge edge = AddNewGraphEdge(vertex, connection.Value);
                    edge.ID += connection.Key + Environment.NewLine;
                }
            }
            int c = graph.Vertices.Count();
            for (int i = 0; i < c; i++)
            {
                if(!graph.Vertices.ElementAt(i).Connections.ContainsValue(graph.Vertices.ElementAt((i + 1)%c)))
                    AddNewGraphEdge(graph.Vertices.ElementAt(i), graph.Vertices.ElementAt((i + 1)%c)).Visibility = Visibility.Hidden;
            }
            
            NotifyPropertyChanged("Graph");

        }
        

        #region Private Methods
        private GuiEdge AddNewGraphEdge(Node from, Node to)
        {
            GuiEdge newEdge = graph.Edges.FirstOrDefault(e => e.Source == from && to == e.Target);
            if (newEdge != null)
                return newEdge;

            newEdge = new GuiEdge(from, to);

            if (graph.Edges.Any(e => e.Source == newEdge.Target && newEdge.Source == e.Target))
                newEdge.IsDoubled = true;
            Graph.AddEdge(newEdge);

            //Graph.Edges.fom
            return newEdge;
        }


        #endregion

        #region Public Properties

        public List<String> LayoutAlgorithmTypes
        {
            get { return layoutAlgorithmTypes; }
        }

        

        public ObservableCollection<string> Statements { get; set; }
        private string _selectedStatement;
        public string Statement
        {
            get { return _selectedStatement; }
            set
            {
                _selectedStatement = value;
                NotifyPropertyChanged("Statement");
            }
        }

        public GuiGraph Graph
        {
            get { return graph; }
            set
            {
                graph = value;
                NotifyPropertyChanged("Graph");
            }
        }
        public Graph ModelGraph
        {
            get { return modelgraph; }
         
        }
        #endregion

        #region INotifyPropertyChanged Implementation

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion
    }
}
